package org.itboys.pay.weixin;

import org.apache.commons.lang3.StringUtils;
import org.itboys.commons.CommonConstants;
import org.itboys.pay.constant.PayConstants;
import org.itboys.pay.tools.XMLUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;

/** 
 * @author 作者 huml 
 * @version 创建时间：2016-4-1 上午11:16:51 
 * 微信支付工具类 
 */
public class WeixinPayUtils {
	
	private static  Logger logger = LoggerFactory.getLogger(WeixinPayUtils.class);
	
	/**
	 * 微信支付前的统一下单和签名    返回的实体中已经含有所需要的参数
	 * @param appid  微信appid
	 * @param mchId  微信商户号
	 * @param openid  openid仅当trade_type=JSAPI时，此参数必传，用户在商户appid下的唯一标识
	 * @param outTradeNo  商户系统内部的订单号,32个字符内、可包含字母 必须
	 * @param spbillCreateIp   APP和网页支付提交用户端ip，Native支付填调用微信支付API的机器IP 必须
	 * @param tradeType 交易类型 trade_type=JSAPI表示H5页面发起调用 必须  JSAPI APP NATIVE(扫码支付)
	 * @param body 商品或支付单简要描述 必须
	 * @param totalFee  订单总金额,只能为整数,单位为分 必须
	 * @param notifyUrl  异步回调链接
	 * @param key  支付秘钥
	 * @return
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	public static WeixinPaySignTool paySign(String appid, String mchId,
			String openid, String outTradeNo,
			String spbillCreateIp, String tradeType, String body,
			String totalFee, String notifyUrl, String productId, String key) throws Exception{
		//创建统一下单实体
		//2017年6月19日，删除product参数
		Unifiedorder unifiedorder = new Unifiedorder(appid, mchId, openid, outTradeNo, spbillCreateIp, tradeType, body, totalFee, notifyUrl, key);
		String param = unifiedorder.getXML();//获得统一下单的xml参数
		logger.info("*****param******"+param);
		String result = WeixinPayUtils.execute(param, Unifiedorder.URL);//发起统一下单访问并获得返回结果
		WeixinPaySignTool tool = null;
		if(StringUtils.isNotBlank(result)){
			Map<String, Object> map = XMLUtil.doXMLParse(result);
			String returnCode = (String)map.get(PayConstants.WeixinPay.RETURN_CODE);
			String resultCode = (String)map.get(PayConstants.WeixinPay.RESULT_CODE);
			if(returnCode.toLowerCase().equals(CommonConstants.SUCCESS) && resultCode.toLowerCase().equals(CommonConstants.SUCCESS)){
				String prepayId = (String)map.get("prepay_id");
				tool = new WeixinPaySignTool(appid, prepayId, key);
				if(tradeType.equals(Unifiedorder.TRADE_TYPE_SCAN)){
					tool.setCodeUrl((String)map.get("code_url"));
				}
				logger.info("**********WeixinPaySignTool*************"+tool.toString());
				
			}else {//统一下单失败
				String returnMsg = (String)map.get(PayConstants.WeixinPay.RETURN_MSG);
				String errCode = (String)map.get(PayConstants.WeixinPay.ERR_CODE);
				String errCodeDes = (String)map.get(PayConstants.WeixinPay.ERR_CODE_DES);
				logger.info("***********"+returnMsg+"**********"+errCode+"************"+errCodeDes);
				throw new RuntimeException("***********"+returnMsg+"**********"+errCode+"************"+errCodeDes);
			}
		} else {
			throw new RuntimeException("***********发起访问错误**********");
		}
		return tool;
	}

	/*public static void main(String[] args){
		try {
			String weixinPaySignTool = nativePay("wxe00e3899f4633ecd", "1403007302", "11111111111", "127.0.0.1", "test",
					"1", "http://admin.fuzion.com", "1", "123456789000000zsmzsmzsmzsm00000", "C:\\Users\\Administrator\\Desktop");
			logger.info("*******************" + JSON.toJSONString(weixinPaySignTool));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}*/

	/**
	 * 微信扫码支付
	 * @param appid
	 * @param mchId
	 * @param outTradeNo
	 * @param spbillCreateIp  调用微信支付API的机器IP
	 * @param body
	 * @param totalFee
	 * @param notifyUrl
	 * @param productId  产品id
	 * @param key
	 * @param path  二维码存放路径
	 * @return
	 * @throws Exception
	 */
/*	public static String nativePay(String appid, String mchId, String outTradeNo,
								 String spbillCreateIp, String body,
								 String totalFee, String notifyUrl, String productId, String key, String path) throws Exception{
		WeixinPaySignTool weixinPaySignTool = paySign(appid, mchId, null, outTradeNo, spbillCreateIp, Unifiedorder.TRADE_TYPE_SCAN, body,
				totalFee, notifyUrl, productId, key);
		return CodeUtils.createTwoDimensionalCode(weixinPaySignTool.getCodeUrl(), outTradeNo, path, 500, 500);
	}*/

	/**
	 * APP微信支付
	 * @param appid  app应用号
	 * @param mchId  商户id
	 * @param outTradeNo  商户订单号
	 * @param spbillCreateIp  ip地址
	 * @param body
	 * @param totalFee
	 * @param notifyUrl
	 * @param key
	 * @return
	 * @throws Exception
	 */
	public static AppPaySignTool appPay(String appid, String mchId,
							  String outTradeNo, String spbillCreateIp,
							  String body, String totalFee, String notifyUrl, String key) throws Exception{
		WeixinPaySignTool weixinPaySignTool = paySign(appid, mchId, StringUtils.EMPTY, outTradeNo, spbillCreateIp,
				Unifiedorder.TRADE_TYPE_APP, body, totalFee, notifyUrl, null, key);

		return new AppPaySignTool(appid, mchId, weixinPaySignTool.getPackage_().replace("prepay_id=", StringUtils.EMPTY), key);
	}


	/**
	 * 执行url访问
	 * @param param  参数
	 * @param url  链接
	 * @return
	 */
	public static String execute(String param, String url) throws Exception {
		URL urll = new URL(url);
		HttpURLConnection connection = (HttpURLConnection) urll.openConnection();

		connection.setDoOutput(true);
		connection.setDoInput(true);
		connection.setUseCaches(false);
		connection.setInstanceFollowRedirects(true);
		connection.setRequestMethod("POST");
		connection.setRequestProperty("Accept", "application/string");
		connection.setRequestProperty("Content-Type", "application/xml");
		connection.connect();
		OutputStreamWriter out = new OutputStreamWriter(connection.getOutputStream(), "UTF-8");

		out.append(param.toString());
		out.flush();
		out.close();

		int length = connection.getContentLength();
		InputStream is = connection.getInputStream();
		String result = StringUtils.EMPTY;
		if (length != -1) {
			byte[] data = new byte[length];
			byte[] temp = new byte[512];
			int readLen = 0;
			int destPos = 0;
			while ((readLen = is.read(temp)) > 0) {
				System.arraycopy(temp, 0, data, destPos, readLen);
				destPos += readLen;
			}
			result = new String(data, "UTF-8");
		}
		return result;
	}
	
}
